home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / ObjectInputStream.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  73.0 KB  |  2,265 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)ObjectInputStream.java    1.78 98/09/24
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. import java.util.ArrayList;
  18. import java.util.Stack;
  19. import java.util.Hashtable;
  20. import java.lang.Math;
  21. import java.lang.reflect.InvocationTargetException;
  22.  
  23. /**
  24.  * An ObjectInputStream deserializes primitive data and objects previously
  25.  * written using an ObjectOutputStream.
  26.  * 
  27.  * ObjectOutputStream and ObjectInputStream can provide an application
  28.  * with persistent storage for graphs of objects when used with a
  29.  * FileOutputStream and FileInputStream respectively.
  30.  * ObjectInputStream is used to recover those objects previously
  31.  * serialized. Other uses include passing objects between hosts using
  32.  * a socket stream or for marshaling and unmarshaling arguments and
  33.  * parameters in a remote communication system.<p>
  34.  *
  35.  * ObjectInputStream ensures that the types of all objects in the
  36.  * graph created from the stream match the classes present in the
  37.  * Java Virtual Machine.  Classes are loaded as required using the
  38.  * standard mechanisms. <p>
  39.  *
  40.  * Only objects that support the java.io.Serializable or
  41.  * java.io.Externalizable interface can be read from streams.
  42.  *
  43.  * The method <STRONG>readObject</STRONG> is used to read an object
  44.  * from the stream.  Java's safe casting should be used to get the
  45.  * desired type.  In Java, strings and arrays are objects and are
  46.  * treated as objects during serialization. When read they need to be
  47.  * cast to the expected type.<p>
  48.  *
  49.  * Primitive data types can be read from the stream using the appropriate
  50.  * method on DataInput. <p>
  51.  * 
  52.  * The default deserialization mechanism for objects restores the
  53.  * contents of each field to the value and type it had when it was written.
  54.  * Fields declared as transient or static are ignored by the
  55.  * deserialization process.  References to other objects cause those
  56.  * objects to be read from the stream as necessary.  Graphs of objects
  57.  * are restored correctly using a reference sharing mechanism.  New
  58.  * objects are always allocated when deserializing, which prevents
  59.  * existing objects from being overwritten. <p>
  60.  *
  61.  * Reading an object is analogous to running the constructors of a new
  62.  * object.  Memory is allocated for the object and initialized to zero
  63.  * (NULL).  No-arg constructors are invoked for the non-serializable
  64.  * classes and then the fields of the serializable classes are
  65.  * restored from the stream starting with the serializable class closest to
  66.  * java.lang.object and finishing with the object's most specifiec
  67.  * class. <p>
  68.  *
  69.  * For example to read from a stream as written by the example in
  70.  * ObjectOutputStream: <br>
  71.  *
  72.  * <PRE>
  73.  *    FileInputStream istream = new FileInputStream("t.tmp");
  74.  *    ObjectInputStream p = new ObjectInputStream(istream);
  75.  *
  76.  *    int i = p.readInt();
  77.  *    String today = (String)p.readObject();
  78.  *    Date date = (Date)p.readObject();
  79.  *
  80.  *    istream.close();
  81.  * </PRE>
  82.  *
  83.  * Classes control how they are serialized by implementing either the
  84.  * java.io.Serializable or java.io.Externalizable interfaces.<P>
  85.  *
  86.  * Implementing the Serializable interface allows object serialization
  87.  * to save and restore the entire state of the object and it allows
  88.  * classes to evolve between the time the stream is written and the time it is
  89.  * read.  It automatically traverses references between objects,
  90.  * saving and restoring entire graphs.
  91.  *
  92.  * Serializable classes that require special handling during the
  93.  * serialization and deserialization process should implement both
  94.  * of these methods:<p>
  95.  *
  96.  * <PRE>
  97.  * private void writeObject(java.io.ObjectOutputStream stream)
  98.  *     throws IOException;
  99.  * private void readObject(java.io.ObjectInputStream stream)
  100.  *     throws IOException, ClassNotFoundException; 
  101.  * </PRE><p>
  102.  *
  103.  * The readObject method is responsible for reading and restoring the
  104.  * state of the object for its particular class using data written to
  105.  * the stream by the corresponding writeObject method.  The method
  106.  * does not need to concern itself with the state belonging to its
  107.  * superclasses or subclasses.  State is restored by reading data from
  108.  * the ObjectInputStream for the individual fields and making
  109.  * assignments to the appropriate fields of the object.  Reading
  110.  * primitive data types is supported by DataInput. <p>
  111.  *
  112.  * Serialization does not read or assign values to the fields of any
  113.  * object that does not implement the java.io.Serializable interface.
  114.  * Subclasses of Objects that are not serializable can be
  115.  * serializable. In this case the non-serializable class must have a
  116.  * no-arg constructor to allow its fields to be initialized.  In this
  117.  * case it is the responsibility of the subclass to save and restore
  118.  * the state of the non-serializable class. It is frequently the case that
  119.  * the fields of that class are accessible (public, package, or
  120.  * protected) or that there are get and set methods that can be used
  121.  * to restore the state. <p>
  122.  *
  123.  * Any exception that occurs while deserializing an object will be
  124.  * caught by the ObjectInputStream and abort the reading process. <p>
  125.  *
  126.  * Implementing the Externalizable interface allows the object to
  127.  * assume complete control over the contents and format of the object's
  128.  * serialized form.  The methods of the Externalizable interface,
  129.  * writeExternal and readExternal, are called to save and restore the
  130.  * objects state.  When implemented by a class they can write and read
  131.  * their own state using all of the methods of ObjectOutput and
  132.  * ObjectInput.  It is the responsibility of the objects to handle any
  133.  * versioning that occurs.
  134.  *
  135.  * @author  Roger Riggs
  136.  * @version 1.78, 09/24/98
  137.  * @see java.io.DataInput
  138.  * @see java.io.ObjectOutputStream
  139.  * @see java.io.Serializable
  140.  * @see <a href="http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/input.doc.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
  141.  * @since   JDK1.1
  142.  */
  143. public class ObjectInputStream extends InputStream
  144.     implements ObjectInput, ObjectStreamConstants
  145.     /**
  146.      * Create an ObjectInputStream that reads from the specified InputStream.
  147.      * The stream header containing the magic number and version number
  148.      * are read from the stream and verified. This method will block
  149.      * until the corresponding ObjectOutputStream has written and flushed the header.
  150.      * @exception StreamCorruptedException The version or magic number are incorrect.
  151.      * @exception IOException An exception occurred in the underlying stream.
  152.      */
  153.     public ObjectInputStream(InputStream in)
  154.     throws IOException, StreamCorruptedException
  155.     {
  156.         enableSubclassImplementation = false;
  157.       /*
  158.        * Save the input stream to read bytes from
  159.        * Create a DataInputStream used to read primitive types.
  160.        * Setup the DataInputStream to read from this ObjectInputStream
  161.        */
  162.     this.in = in;
  163.     dis  = new DataInputStream(this); 
  164.     readStreamHeader();
  165.     resetStream();
  166.     }
  167.  
  168.     /**
  169.      * Provide a way for subclasses that are completely reimplementing
  170.      * ObjectInputStream to not have to allocate private data just used by
  171.      * this implementation of ObjectInputStream.
  172.      *
  173.      * <p>If there is a security manager installed, this method first calls the
  174.      * security manager's <code>checkPermission</code> method with the
  175.      * <code>SerializablePermission("enableSubclassImplementation")</code>
  176.      * permission to ensure it's ok to enable subclassing.
  177.      *
  178.      * @exception IOException   Thrown if not called by a subclass.
  179.      * @throws SecurityException
  180.      *    if a security manager exists and its 
  181.      *    <code>checkPermission</code> method denies
  182.      *    enabling subclassing.
  183.      *
  184.      * @see SecurityManager#checkPermission
  185.      * @see java.security.SerializablePermission
  186.      */
  187.     protected ObjectInputStream() throws IOException, SecurityException {
  188.     SecurityManager sm = System.getSecurityManager();
  189.     if (sm != null) sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  190.     enableSubclassImplementation = true;
  191.     }
  192.  
  193.     /**
  194.      * Read an object from the ObjectInputStream.
  195.      * The class of the object, the signature of the class, and the values
  196.      * of the non-transient and non-static fields of the class and all
  197.      * of its supertypes are read.  Default deserializing for a class can be
  198.      * overriden using the writeObject and readObject methods.
  199.      * Objects referenced by this object are read transitively so
  200.      * that a complete equivalent graph of objects is reconstructed by 
  201.      * readObject. <p>
  202.      *
  203.      * The root object is completly restored when all of its fields
  204.      * and the objects it references are completely restored.  At this
  205.      * point the object validation callbacks are executed in order
  206.      * based on their registered priorities. The callbacks are
  207.      * registered by objects (in the readObject special methods)
  208.      * as they are individually restored.
  209.      *
  210.      * Exceptions are thrown for problems with the InputStream and for classes
  211.      * that should not be deserialized.  All exceptions are fatal to the 
  212.      * InputStream and leave it in an indeterminate state; it is up to the 
  213.      * caller to ignore or recover the stream state.
  214.      * @exception java.lang.ClassNotFoundException Class of a serialized object
  215.      *      cannot be found.
  216.      * @exception InvalidClassException Something is wrong with a class used by
  217.      *     serialization.
  218.      * @exception StreamCorruptedException Control information in the
  219.      *     stream is inconsistent.
  220.      * @exception OptionalDataException Primitive data was found in the 
  221.      * stream instead of objects.
  222.      * @exception IOException Any of the usual Input/Output related exceptions.
  223.      */
  224.     public final Object readObject()
  225.     throws OptionalDataException, ClassNotFoundException, IOException {
  226.     if (enableSubclassImplementation)
  227.         return readObjectOverride();
  228.     else {
  229.  
  230.         /* require local Class for object by default. */
  231.         return readObject(true);
  232.     }
  233.     }
  234.  
  235.     /**
  236.      * This method is called by trusted subclasses of ObjectOutputStream
  237.      * that constructed ObjectOutputStream using the 
  238.      * protected no-arg constructor. The subclass is expected to provide
  239.      * an override method with the modifier "final".
  240.      *
  241.      * @return the Object read from the stream.
  242.      *
  243.      * @see #ObjectInputStream()
  244.      * @see #readObject()
  245.      * @since JDK 1.2
  246.      */
  247.     protected Object readObjectOverride()
  248.      throws OptionalDataException, ClassNotFoundException, IOException 
  249.     {
  250.     return null;
  251.     }
  252.  
  253.     /*
  254.      * Private implementation of Read an object from the ObjectInputStream.
  255.      *
  256.      * @param requireLocalClass If false, do not throw ClassNotFoundException
  257.      *                          when local class does not exist.
  258.      *
  259.      * @since     JDK1.2
  260.      */
  261.     private final Object readObject(boolean requireLocalClass)
  262.     throws OptionalDataException, ClassNotFoundException, IOException
  263.     {
  264.     /* If the stream is in blockData mode and there's any data
  265.      * left throw an exception to report how much there is.
  266.      */
  267.     if (blockDataMode) {
  268.         /* Can't use member method available() since it depends on the unreliable
  269.          *  method InputStream.available().
  270.          */
  271.         if (count == 0)
  272.         refill();
  273.         if (count > 0)
  274.         throw new OptionalDataException(count);
  275.     }
  276.     
  277.     /*
  278.      * Look ahead now to absorb any pending reset's.
  279.      * Before changing the state.
  280.      */
  281.     peekCode();
  282.  
  283.     /* Save the current state and get ready to read an object. */
  284.     Object prevObject = currentObject;
  285.     ObjectStreamClass prevClass = currentClassDesc;
  286.     boolean prevBlockDataMode = setBlockData(false);
  287.     
  288.     recursionDepth++;    // Entering
  289.     Object obj = null;
  290.  
  291.     /* 
  292.      * Check for reset, handle it before reading an object.
  293.      */
  294.  
  295.     byte rcode;
  296.     rcode = readCode();
  297.     try {
  298.         /*
  299.          * Dispatch on the next code in the stream.
  300.          */
  301.         int wireoffset = -1;
  302.  
  303.         switch (rcode) {
  304.         
  305.         case TC_NULL:
  306.         obj = null;
  307.         break;
  308.         
  309.         case TC_REFERENCE: 
  310.         /* This is a reference to a pre-existing object */
  311.         wireoffset = readInt() - baseWireHandle; 
  312.         
  313.         try {
  314.             obj = wireHandle2Object.get(wireoffset);
  315.         } catch (ArrayIndexOutOfBoundsException e) {
  316.             throw new StreamCorruptedException("Reference to object never serialized.");
  317.         }
  318.         break;
  319.         
  320.         case TC_STRING:
  321.         {
  322.             obj = readUTF(); 
  323.             Object localObj = obj;
  324.             wireoffset = assignWireOffset(obj);
  325.             /* Allow subclasses to replace the object */
  326.             if (enableResolve) {
  327.             obj = resolveObject(obj);
  328.             }
  329.  
  330.             if (obj != localObj)
  331.             wireHandle2Object.set(wireoffset, obj);
  332.         }
  333.         break;
  334.         
  335.         case TC_CLASS:
  336.         ObjectStreamClass v =
  337.             (ObjectStreamClass)readObject(requireLocalClass);
  338.         if (v == null) {
  339.             /*
  340.              * No class descriptor in stream or class not serializable
  341.              */
  342.             throw new StreamCorruptedException("Class not in stream");
  343.         }
  344.         obj = v.forClass();
  345.         if (obj == null && requireLocalClass) {
  346.             throw new ClassNotFoundException(v.getName());
  347.         }
  348.         assignWireOffset(obj);
  349.         break;
  350.         
  351.         case TC_CLASSDESC:
  352.         obj = inputClassDescriptor();
  353.         break;
  354.         
  355.         case TC_ARRAY:
  356.         wireoffset = inputArray(requireLocalClass);
  357.         obj = currentObject;
  358.         /* Allow subclasses to replace the object */
  359.         if (enableResolve) {
  360.             obj = resolveObject(obj);
  361.         }
  362.  
  363.         if (obj != currentObject)
  364.             wireHandle2Object.set(wireoffset, obj);
  365.         break;
  366.         
  367.         case TC_OBJECT:
  368.         wireoffset = inputObject(requireLocalClass);
  369.         obj = currentObject;
  370.  
  371.         /* Allow the object to resolve itself. */
  372.         if (currentObject != null && 
  373.             currentClassDesc != null && 
  374.             currentClassDesc.isResolvable()) {
  375.             obj = 
  376.             ObjectStreamClass.invokeMethod(currentClassDesc.readResolveMethod,
  377.                                obj, null);
  378.         }
  379.  
  380.         /* Allow subclasses to replace the object */
  381.         if (enableResolve) {
  382.             obj = resolveObject(obj);
  383.         }
  384.  
  385.         if (obj != currentObject)
  386.             wireHandle2Object.set(wireoffset, obj);
  387.         break;
  388.         
  389.         case TC_ENDBLOCKDATA:
  390.         if (!prevBlockDataMode)
  391.             throw new StreamCorruptedException("Unexpected end of block data");
  392.         pushbackCode(TC_ENDBLOCKDATA);
  393.         count = -1;    /* Flag EOF */ 
  394.         throw new OptionalDataException(true);
  395.         
  396.         case TC_BLOCKDATA:
  397.         case TC_BLOCKDATALONG:
  398.         if (rcode == TC_BLOCKDATALONG) { /* long block: 32 bit size */
  399.             int b3 = in.read();
  400.             int b2 = in.read();
  401.             int b1 = in.read();
  402.             int b0 = in.read();
  403.             if ((b3 | b2 | b1 | b0) < 0)
  404.             throw new StreamCorruptedException("EOF expecting count");
  405.             count = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
  406.             if (count < 0)
  407.             throw new StreamCorruptedException("Negative block data size");
  408.         } else {            /* normal block: 8 bit size */
  409.             count = in.read();
  410.             if (count < 0)
  411.             throw new StreamCorruptedException("EOF expecting count");
  412.         }
  413.  
  414.             if (!prevBlockDataMode)
  415.             throw new StreamCorruptedException("Unexpected blockdata");
  416.         
  417.         throw new OptionalDataException(count);
  418.         
  419.         case TC_EXCEPTION:
  420.         /* An exception happened during writing, reset the
  421.          * stream, read the exception, reset the stream and
  422.          * throw a writeAbortedException with the exception
  423.          * that was read.
  424.          */
  425.         resetStream();
  426.         IOException ee = (IOException)readObject();
  427.         resetStream();
  428.         throw new WriteAbortedException("Writing aborted by exception", ee);
  429.  
  430.         default:
  431.         throw new StreamCorruptedException("Unknown code in readObject " + rcode);
  432.         }
  433.     } catch (OptionalDataException optdata) {
  434.         /* OptionalDataExceptions won't terminate everything.
  435.          * so just rethrow it.
  436.          */
  437.         throw optdata;
  438.     } catch(IOException ee) {
  439.         if (abortIOException == null && abortClassNotFoundException == null)
  440.         abortIOException = ee;
  441.     } catch(ClassNotFoundException ee) {
  442.         if (abortIOException == null && abortClassNotFoundException == null)
  443.         abortClassNotFoundException = ee;
  444.     } finally {
  445.         recursionDepth --;
  446.         currentObject = prevObject;
  447.         currentClassDesc = prevClass;
  448.         currentClass = currentClassDesc != null ? 
  449.         currentClassDesc.forClass() : null;
  450.         setBlockData(prevBlockDataMode);
  451.     }
  452.     
  453.     /* Check for thrown exceptions and re-throw them, clearing them if
  454.      * this is the last recursive call .
  455.      */
  456.     IOException exIOE = abortIOException;
  457.     if (recursionDepth == 0)
  458.         abortIOException = null;
  459.     if (exIOE != null)
  460.         throw exIOE;
  461.  
  462.     
  463.     ClassNotFoundException exCNF = abortClassNotFoundException;
  464.     if (recursionDepth == 0)
  465.         abortClassNotFoundException = null;
  466.     if (exCNF != null) {
  467.         throw exCNF;
  468.     }
  469.     
  470.     // Check if this is the last nested read, if so
  471.     // Call the validations
  472.     if (recursionDepth == 0) {
  473.         doValidations();
  474.     }
  475.  
  476.     return obj;
  477.     }
  478.  
  479.     /**
  480.      * Read the non-static and non-transient fields of the current class
  481.      * from this stream.  This may only be called from the readObject method
  482.      * of the class being deserialized. It will throw the NotActiveException
  483.      * if it is called otherwise.
  484.      *
  485.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  486.      *              object could not be found.
  487.      * @exception IOException        if an I/O error occurs.
  488.      * @exception NotActiveException if the stream is not currently reading
  489.      *              objects.
  490.      */
  491.     public void defaultReadObject()
  492.     throws IOException, ClassNotFoundException, NotActiveException
  493.     {
  494.     if (currentObject == null || currentClassDesc == null)
  495.         throw new NotActiveException("defaultReadObject");
  496.  
  497.     ObjectStreamField[] fields = 
  498.         currentClassDesc.getFieldsNoCopy();
  499.     if (fields.length > 0) {
  500.         boolean prevmode = setBlockData(false);
  501.         inputClassFields(currentObject, currentClass, fields);
  502.         setBlockData(prevmode);
  503.     }
  504.     }
  505.     
  506.     /**
  507.      * Reads the persistent fields from the stream and makes them 
  508.      * available by name.
  509.      * 
  510.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  511.      *              object could not be found.
  512.      * @exception IOException        if an I/O error occurs.
  513.      * @exception NotActiveException if the stream is not currently reading
  514.      *              objects.
  515.      * @since JDK 1.2
  516.      */
  517.     public ObjectInputStream.GetField readFields()
  518.         throws IOException, ClassNotFoundException, NotActiveException
  519.     {
  520.     if (currentObject == null || currentClassDesc == null)
  521.         throw new NotActiveException("defaultReadObject");
  522.  
  523.     // TBD: Interlock w/ defaultReadObject
  524.  
  525.     GetFieldImpl curr = new GetFieldImpl(currentClassDesc);
  526.     currentGetFields = curr;
  527.     boolean prevmode = setBlockData(false);
  528.     curr.read(this);
  529.     setBlockData(prevmode);
  530.     return curr;
  531.     }
  532.  
  533.     /**
  534.      * Register an object to be validated before the graph is
  535.      * returned.  While similar to resolveObject these validations are
  536.      * called after the entire graph has been reconstituted.
  537.      * Typically, a readObject method will register the object with
  538.      * the stream so that when all of the objects are restored a final
  539.      * set of validations can be performed.
  540.      * @param obj the object to receive the validation callback.
  541.      * @param prio controls the order of callbacks;zero is a good default.
  542.      * Use higher numbers to be called back earlier, lower numbers for later
  543.      * callbacks. Within a priority, callbacks are processed in no
  544.      * particular order.
  545.      *
  546.      * @exception NotActiveException The stream is not currently reading 
  547.      * objects so it is invalid to register a callback.
  548.      * @exception InvalidObjectException The validation object is null.
  549.      */
  550.     public synchronized void registerValidation(ObjectInputValidation obj,
  551.                         int prio)
  552.     throws NotActiveException, InvalidObjectException
  553.     {
  554.     if (recursionDepth == 0) {
  555.         throw new NotActiveException("readObject not Active");
  556.     }
  557.     if (obj == null) {
  558.         throw new InvalidObjectException("Null is not a valid callback object");
  559.     }
  560.  
  561.     ValidationCallback cb = new ValidationCallback(obj, prio);
  562.  
  563.     if (callbacks == null) {
  564.         callbacks = new ArrayList();
  565.     }
  566.     // insert at the end if the priority is less than or equal to
  567.     // the last element.
  568.     if (callbacks.isEmpty() ||
  569.         ((ValidationCallback)(callbacks.get(callbacks.size()-1))).priority >= prio) {
  570.         callbacks.add(cb);
  571.         return;
  572.     }
  573.  
  574.     // search for the element with priority that is <= to the new
  575.     // priority, insert before it. 
  576.     int size = callbacks.size();
  577.     for (int i = 0; i < size; i++) {
  578.         ValidationCallback curr = (ValidationCallback)callbacks.get(i);
  579.         if (curr.priority <= prio) {
  580.         callbacks.add(i, cb);
  581.         break;
  582.         }
  583.     }
  584.     }
  585.  
  586.     /*
  587.      * If any validations are pending, do them and cleanup the validation vector
  588.      * if an exception is raised, it is passed on to abort the deserialization.
  589.      */
  590.     private void doValidations() throws InvalidObjectException {
  591.     if (callbacks == null)
  592.         return;
  593.     
  594.     int size = callbacks.size();
  595.     for (int i = 0; i < size; i++) {
  596.         ValidationCallback curr = (ValidationCallback)callbacks.get(i);
  597.         curr.callback.validateObject();
  598.     }
  599.     callbacks.clear();
  600.     }
  601.  
  602.     /**
  603.      * Load the local class equivalent of the specified stream class description.
  604.      *
  605.      * Subclasses may implement this method to allow classes to be
  606.      * fetched from an alternate source. 
  607.      *
  608.      * The corresponding method in ObjectOutputStream is
  609.      * annotateClass.  This method will be invoked only once for each
  610.      * unique class in the stream.  This method can be implemented by
  611.      * subclasses to use an alternate loading mechanism but must
  612.      * return a Class object.  Once returned, the serialVersionUID of the
  613.      * class is compared to the serialVersionUID of the serialized class.
  614.      * If there is a mismatch, the deserialization fails and an exception
  615.      * is raised. <p>
  616.      *
  617.      * By default the class name is resolved relative to the class
  618.      * that called readObject. <p>
  619.      *
  620.      * @exception ClassNotFoundException If class of
  621.      * a serialized object cannot be found.
  622.      */
  623.     protected Class resolveClass(ObjectStreamClass v)
  624.     throws IOException, ClassNotFoundException
  625.     {
  626.     /* Resolve by looking up the stack for a non-zero class
  627.      * loader. If not found use the system class loader.
  628.      */
  629.     return loadClass0(null, v.getName());
  630.     }
  631.  
  632.     /* Resolve a class name relative to the specified class.  If the
  633.      * class is null find the first available class loader up the
  634.      * stack.  This will resolve classes relative to the caller of
  635.      * ObjectInputStream instead of the itself. Classes must be
  636.      * loaded/resolved relative to the application.
  637.      */
  638.     private native Class loadClass0(Class cl, String classname)
  639.     throws ClassNotFoundException;
  640.  
  641.     /**
  642.      * This method will allow trusted subclasses of ObjectInputStream
  643.      * to substitute one object for another during
  644.      * deserialization. Replacing objects is disabled until
  645.      * enableResolveObject is called. The enableResolveObject method
  646.      * checks that the stream requesting to resolve object can be
  647.      * trusted. Every reference to serializable objects is passed to
  648.      * resolveObject.  To insure that the private state of objects is
  649.      * not unintentionally exposed only trusted streams may use
  650.      * resolveObject. <p>
  651.      *
  652.      * This method is called after an object has been read but before it is
  653.      * returned from readObject.  The default resolveObject method
  654.      * just returns the new object. <p>
  655.      *
  656.      * When a subclass is replacing objects it must insure that the
  657.      * substituted object is compatible with every field where the
  658.      * reference will be stored.  Objects whose type is not a subclass
  659.      * of the type of the field or array element abort the
  660.      * serialization by raising an exception and the object is not be
  661.      * stored. <p>
  662.      *
  663.      * This method is called only once when each object is first encountered.
  664.      * All subsequent references to the object will be redirected to the
  665.      * new object. <P>
  666.      *
  667.      * @exception IOException Any of the usual Input/Output exceptions.
  668.      */
  669.     protected Object resolveObject(Object obj)
  670.         throws IOException
  671.     {
  672.     return obj;
  673.     }
  674.  
  675.  
  676.     /**
  677.      * Enable the stream to allow objects read from the stream to be replaced.
  678.      * 
  679.      * When enabled, the resolveObject method is called for every object
  680.      * being deserialized.
  681.      *
  682.      * If <i>enable</i> is true, and there is a security manager installed, 
  683.      * this method first calls the
  684.      * security manager's <code>checkPermission</code> method with the
  685.      * <code>SerializablePermission("enableSubstitution")</code>
  686.      * permission to ensure it's ok to 
  687.      * enable the stream to allow objects read from the stream to be replaced.
  688.      * 
  689.      * @throws SecurityException
  690.      *    if a security manager exists and its 
  691.      *    <code>checkPermission</code> method denies
  692.      *    enabling the stream to allow objects read from the stream to be replaced.
  693.      *
  694.      * @see SecurityManager#checkPermission
  695.      * @see java.security.SerializablePermission
  696.      */
  697.     protected boolean enableResolveObject(boolean enable)
  698.     throws SecurityException
  699.     {
  700.     boolean previous = enableResolve;
  701.     if (enable) {
  702.         SecurityManager sm = System.getSecurityManager();
  703.         if (sm != null) sm.checkPermission(SUBSTITUTION_PERMISSION);
  704.         enableResolve = true;
  705.     } else {
  706.         enableResolve = false;
  707.     }
  708.     return previous;
  709.     }
  710.  
  711.  
  712.     /**
  713.      * The readStreamHeader method is provided to allow subclasses to
  714.      * read and verify their own stream headers. It reads and
  715.      * verifies the magic number and version number.
  716.      */
  717.     protected void readStreamHeader()
  718.     throws IOException, StreamCorruptedException
  719.     {
  720.     short incoming_magic = 0;
  721.     short incoming_version = 0;
  722.     try {
  723.         incoming_magic = readShort();
  724.         incoming_version = readShort();
  725.     } catch (EOFException e) {
  726.         throw new StreamCorruptedException("Caught EOFException " +
  727.                            "while reading the stream header");
  728.     } 
  729.     if (incoming_magic != STREAM_MAGIC)
  730.         throw new StreamCorruptedException("InputStream does not contain a serialized object");
  731.     
  732.     if (incoming_version != STREAM_VERSION)
  733.         throw new StreamCorruptedException("Version Mismatch, Expected " +
  734.                            STREAM_VERSION + " and got " +
  735.                            incoming_version);
  736.     }
  737.  
  738.     /*
  739.      * Read a ObjectStreamClass from the stream, it may recursively
  740.      * create other ObjectStreamClasses for the classes it references.
  741.      */
  742.     private ObjectStreamClass inputClassDescriptor()
  743.     throws IOException, InvalidClassException, ClassNotFoundException
  744.     {
  745.  
  746.     /* Read the class name and hash */
  747.     Class aclass;
  748.     String classname = readUTF(); 
  749.     long hash = readLong();
  750.  
  751.     /* Read a new class version descriptor from the stream */
  752.     ObjectStreamClass v = new ObjectStreamClass(classname, hash);
  753.  
  754.     /* Assign the wire handle for this ObjectStreamClass and read it */
  755.     int wireoffset = assignWireOffset(v); 
  756.     v.read(this);
  757.  
  758.     /* Switch to BlockDataMode and call resolveClass.
  759.      * It may raise ClassNotFoundException.
  760.      * Consume any extra data or objects left by resolve class and
  761.      * read the endOfBlockData. Then switch out of BlockDataMode.
  762.      */
  763.     boolean prevMode = setBlockData(true);
  764.     try {
  765.         aclass = resolveClass((ObjectStreamClass)v);
  766.     } catch (ClassNotFoundException e) {
  767.         /* if the most derived class, this exception will be thrown at a later time. */
  768.         aclass = null;
  769.     } catch (NoClassDefFoundError e) {
  770.         /* This exception was thrown when looking for an array of class,
  771.          * and class could not be found.
  772.          */
  773.         aclass = null;
  774.     }
  775.     SkipToEndOfBlockData();
  776.     prevMode = setBlockData(prevMode);
  777.  
  778.  
  779.     /* Verify that the class returned is "compatible" with
  780.      * the class description.  i.e. the name and hash match.
  781.      * Set the class this ObjectStreamClass will use to create 
  782.      * instances.
  783.      */
  784.     v.setClass(aclass);
  785.  
  786.     /* Get the superdescriptor of this one and it set it.
  787.      */
  788.     ObjectStreamClass superdesc = (ObjectStreamClass)readObject();
  789.     v.setSuperclass(superdesc);
  790.  
  791.     return v;
  792.     }
  793.  
  794.     /* Private routine to read in an array. Called from inputObject
  795.      * after the typecode has been read from the stream.
  796.      */
  797.     private int inputArray(boolean requireLocalClass)
  798.     throws IOException, ClassNotFoundException
  799.     {
  800.     /* May raise ClassNotFoundException */
  801.     ObjectStreamClass v = (ObjectStreamClass)readObject();
  802.     
  803.     Class arrayclass = v.forClass();
  804.     if (arrayclass == null && requireLocalClass)
  805.         throw new ClassNotFoundException(v.getName());
  806.  
  807.     /* This can't be done with new because only the top level array
  808.      * is needed and the type must be set properly.
  809.      * the lower level arrays will be created when they are read.
  810.      */
  811.     int length = readInt();
  812.         currentObject = (arrayclass == null) ?
  813.         null : allocateNewArray(arrayclass, length);
  814.     int wireoffset = assignWireOffset(currentObject);
  815.     
  816.     /* Read in the values from the array,
  817.      * It dispatches using the type and read using the read* methods.
  818.      */
  819.     int i;
  820.     if (arrayclass != null
  821.         && arrayclass.getComponentType().isPrimitive()) {
  822.         Class type = arrayclass.getComponentType();
  823.         /* Arrays of primitive types read data in blocks and
  824.          * decode the data types from the buffer.
  825.              */
  826.         if (buffer == null)
  827.         buffer = new byte[1024];
  828.         int offset = buffer.length;
  829.         int buflen = buffer.length;
  830.  
  831.         if (type == Boolean.TYPE) {
  832.         boolean[] array = (boolean[])currentObject;
  833.         for (i = 0; i < length; i++) {
  834.             if (offset >= buflen) {
  835.             int readlen = Math.min(length-i, buflen);
  836.             readFully(buffer, 0, readlen);
  837.             offset = 0;
  838.             }
  839.             array[i] = (buffer[offset] != 0);
  840.             offset += 1;
  841.         }
  842.         } else if (type == Byte.TYPE) {
  843.         byte[] array = (byte[])currentObject;
  844.         int ai = 0;
  845.         while (ai < length) {
  846.             int readlen = Math.min(length-ai, buflen);
  847.             readFully(buffer, 0, readlen);
  848.             System.arraycopy(buffer, 0, array, ai, readlen);
  849.             ai += readlen;
  850.         }
  851.         } else if (type == Short.TYPE) {
  852.         short[] array = (short[])currentObject;
  853.         for (i = 0; i < length; i++) {
  854.             if (offset > buflen - 2) {
  855.             int readlen = Math.min((length-i)*2, buflen);
  856.             readFully(buffer, 0, readlen);
  857.             offset = 0;
  858.             }
  859.             array[i] = (short)(((buffer[offset] & 0xff) << 8) +
  860.                        ((buffer[offset+1] & 0xff) << 0));
  861.             offset += 2;
  862.         }
  863.         } else if (type == Integer.TYPE) {
  864.         int[] array = (int[])currentObject;
  865.         for (i = 0; i < length; i++) {
  866.             if (offset > buflen - 4) {
  867.             int readlen = Math.min((length-i)*4, buflen);
  868.             readFully(buffer, 0, readlen);
  869.             offset = 0;
  870.             }
  871.             array[i] = (((buffer[offset] & 0xff) << 24) +
  872.                 ((buffer[offset+1] & 0xff) << 16) +
  873.                 ((buffer[offset+2] & 0xff) << 8) +
  874.                 ((buffer[offset+3] & 0xff) << 0));
  875.             offset += 4;
  876.         }
  877.         } else if (type == Long.TYPE) {
  878.         long[] array = (long[])currentObject;
  879.         for (i = 0; i < length; i++) {
  880.             if (offset > buflen - 8) {
  881.             int readlen = Math.min((length-i)*8, buflen);
  882.             readFully(buffer, 0, readlen);
  883.             offset = 0;
  884.             }
  885.             int upper = (((buffer[offset] & 0xff) << 24) +
  886.                  ((buffer[offset+1] & 0xff) << 16) +
  887.                  ((buffer[offset+2] & 0xff) << 8) +
  888.                  ((buffer[offset+3] & 0xff) << 0));
  889.             int lower = (((buffer[offset+4] & 0xff) << 24) +
  890.                  ((buffer[offset+5] & 0xff) << 16) +
  891.                  ((buffer[offset+6] & 0xff) << 8) +
  892.                  ((buffer[offset+7] & 0xff) << 0));
  893.             array[i] = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  894.             offset += 8;
  895.         }
  896.         } else if (type == Float.TYPE) {
  897.         float[] array = (float[])currentObject;
  898.         for (i = 0; i < length; i++) {
  899.             if (offset > buflen - 4) {
  900.             int readlen = Math.min((length-i)*4, buflen);
  901.             readFully(buffer, 0, readlen);
  902.             offset = 0;
  903.             }
  904.             int value = (((buffer[offset] & 0xff) << 24) +
  905.                  ((buffer[offset+1] & 0xff) << 16) +
  906.                  ((buffer[offset+2] & 0xff) << 8) +
  907.                  ((buffer[offset+3] & 0xff) << 0));
  908.             offset += 4;
  909.             array[i] = Float.intBitsToFloat(value);
  910.         }
  911.         } else if (type == Double.TYPE) {
  912.         double[] array = (double[])currentObject;
  913.         for (i = 0; i < length; i++) {
  914.             if (offset > buflen - 8) {
  915.             int readlen = Math.min((length-i)*8, buflen);
  916.             readFully(buffer, 0, readlen);
  917.             offset = 0;
  918.             }
  919.             int upper = (((buffer[offset] & 0xff) << 24) +
  920.                  ((buffer[offset+1] & 0xff) << 16) +
  921.                  ((buffer[offset+2] & 0xff) << 8) +
  922.                  ((buffer[offset+3] & 0xff) << 0));
  923.             int lower = (((buffer[offset+4] & 0xff) << 24) +
  924.                  ((buffer[offset+5] & 0xff) << 16) +
  925.                  ((buffer[offset+6] & 0xff) << 8) +
  926.                  ((buffer[offset+7] & 0xff) << 0));
  927.             offset += 8;
  928.             array[i] = Double.longBitsToDouble((((long)upper) << 32) +
  929.                                (lower & 0xFFFFFFFFL));
  930.         }
  931.         } else if (type == Character.TYPE) {
  932.         char[] array = (char[])currentObject;
  933.         for (i = 0; i < length; i++) {
  934.             if (offset > buflen - 2) {
  935.             int readlen = Math.min((length-i)*2, buflen);
  936.             readFully(buffer, 0, readlen);
  937.             offset = 0;
  938.             }
  939.             array[i] = (char)(((buffer[offset] & 0xff) << 8) +
  940.                       ((buffer[offset+1] & 0xff) << 0));
  941.             offset += 2;
  942.         }
  943.         } else {
  944.         throw new InvalidClassException(arrayclass.getName());
  945.         }
  946.     } else {        // Is array of objects
  947.         Object[] array = (Object[])currentObject;
  948.         boolean requiresLocalClass = (arrayclass != null);
  949.         for (i = 0; i < length; i++) {
  950.         Object obj = readObject(requiresLocalClass);
  951.         if (array != null)
  952.             array[i] = obj;
  953.         }
  954.     }
  955.  
  956.     return wireoffset;
  957.     }
  958.  
  959.     /*
  960.      * Read an instance of a class from the stream
  961.      * The new object typecode has already been read and used to dispatch to here.
  962.      * The ObjectStreamClass for the class is read and the class
  963.      * of the object retrieved from it.
  964.      * A new object is created of the specified class and
  965.      * each serializable class is processed using either
  966.      * the default serialization methods or class defined special methods
  967.      * if they have been defined.
  968.      * The handle for the object is returned, the object itself is in currentObject.
  969.      */
  970.     private int inputObject(boolean requireLocalClass)
  971.     throws IOException, ClassNotFoundException
  972.     {
  973.     int handle = -1;
  974.     /*
  975.      * Get the descriptor and then class of the incoming object.
  976.      */
  977.     currentClassDesc = (ObjectStreamClass)readObject();
  978.     currentClass = currentClassDesc.forClass();
  979.     if (currentClass == null && requireLocalClass)
  980.         throw new ClassNotFoundException(currentClassDesc.getName());
  981.     
  982.     if (requireLocalClass)
  983.         currentClassDesc.verifyInstanceDeserialization();
  984.     
  985.     /* If Externalizable,
  986.      *  Create an instance and tell it to read its data.
  987.      * else,
  988.      *  Handle it as a serializable class.
  989.      */
  990.     if (currentClassDesc.isExternalizable()) {
  991.         try {
  992.         currentObject = (currentClass == null) ?
  993.                       null : allocateNewObject(currentClass, currentClass);
  994.         handle = assignWireOffset(currentObject);
  995.         boolean prevmode = blockDataMode;
  996.         try {
  997.             if (currentClassDesc.hasExternalizableBlockDataMode()) {
  998.             prevmode = setBlockData(true);
  999.             }
  1000.  
  1001.             if (currentObject != null) {
  1002.             Externalizable ext = (Externalizable)currentObject;
  1003.             ext.readExternal(this);
  1004.             }
  1005.         } finally {
  1006.             if (currentClassDesc.hasExternalizableBlockDataMode()) {
  1007.             SkipToEndOfBlockData();
  1008.             setBlockData(prevmode);
  1009.             }
  1010.         }
  1011.         } catch (NoSuchMethodError e) {
  1012.         throw new InvalidClassException(currentClass.getName(),
  1013.                         e.getMessage());
  1014.         } catch (IllegalAccessException e) {
  1015.         throw new InvalidClassException(currentClass.getName(),
  1016.                         "IllegalAccessException");
  1017.         } catch (InstantiationException e) {
  1018.         throw new InvalidClassException(currentClass.getName(),
  1019.                         "InstantiationException");
  1020.         }
  1021.     } else {
  1022.         /* Count number of classes and descriptors we might have
  1023.          * to work on.
  1024.          */
  1025.         ObjectStreamClass currdesc = currentClassDesc;
  1026.         Class currclass = currentClass;
  1027.  
  1028.         int spBase = spClass;    // current top of stack
  1029.  
  1030.         /* The object's classes should be processed from supertype to subtype
  1031.          * Push all the clases of the current object onto a stack.
  1032.          * Note that only the serializable classes are represented
  1033.          * in the descriptor list. 
  1034.          *
  1035.          * Handle versioning where one or more supertypes of
  1036.          * have been inserted or removed.  The stack will
  1037.          * contain pairs of descriptors and the corresponding
  1038.          * class.  If the object has a class that did not occur in
  1039.          * the original the descriptor will be null.  If the
  1040.          * original object had a descriptor for a class not
  1041.          * present in the local hierarchy of the object the class will be
  1042.          * null.
  1043.          *
  1044.          */
  1045.  
  1046.         /*
  1047.          * This is your basic diff pattern, made simpler
  1048.          * because reordering is not allowed.
  1049.          */
  1050.         for (currdesc = currentClassDesc, currclass = currentClass;
  1051.          currdesc != null;
  1052.          currdesc = currdesc.getSuperclass()) {
  1053.  
  1054.         /*
  1055.          * Search the classes to see if the class of this
  1056.          * descriptor appears further up the hierarchy. Until
  1057.          * it's found assume its an inserted class.  If it's
  1058.          * not found, its the descriptor's class that has been
  1059.          * removed.
  1060.          */
  1061.         Class cc = currdesc.forClass();
  1062.         Class cl;
  1063.         for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
  1064.             if (cc == cl) {
  1065.             // found a superclass that matches this descriptor
  1066.             break;
  1067.             } else {
  1068.             /* Ignore a class that doesn't match.  No
  1069.              * action is needed since it is already
  1070.              * initialized.
  1071.              */
  1072.             }
  1073.         }
  1074.         /* Test if there is room for this new entry.
  1075.          * If not, double the size of the arrays and copy the contents.
  1076.          */
  1077.         spClass++;
  1078.         if (spClass >= classes.length) {
  1079.             int newlen = classes.length * 2;
  1080.             Class[] newclasses = new Class[newlen];
  1081.             ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
  1082.  
  1083.             System.arraycopy(classes, 0,
  1084.                  newclasses, 0,
  1085.                  classes.length);
  1086.             System.arraycopy(classdesc, 0,
  1087.                      newclassdesc, 0,
  1088.                      classes.length);
  1089.  
  1090.             classes = newclasses;
  1091.             classdesc = newclassdesc;
  1092.         }
  1093.  
  1094.         if (cl == null) {
  1095.             /* Class not found corresponding to this descriptor.
  1096.              * Pop off all the extra classes pushed.
  1097.              * Push the descriptor and a null class.
  1098.              */
  1099.             classdesc[spClass] = currdesc;
  1100.             classes[spClass] = null;
  1101.         } else {
  1102.                    /* Current class descriptor matches current class.
  1103.              * Some classes may have been inserted.
  1104.              * Record the match and advance the class, continue
  1105.              * with the next descriptor.
  1106.              */
  1107.             classdesc[spClass] = currdesc;
  1108.             classes[spClass] = cl;
  1109.             currclass = cl.getSuperclass();
  1110.         }
  1111.         }
  1112.  
  1113.         /* Allocate a new object.  The object is only constructed
  1114.          * above the highest serializable class and is set to
  1115.          * default values for all more specialized classes.
  1116.          * Remember the next wirehandle goes with the new object
  1117.          */
  1118.         try {
  1119.         currentObject = (currentClass == null) ?
  1120.                          null : allocateNewObject(currentClass, currclass);
  1121.         } catch (NoSuchMethodError e) {
  1122.         throw new InvalidClassException(currclass.getName(),
  1123.                         e.getMessage());
  1124.         } catch (IllegalAccessException e) {
  1125.         throw new InvalidClassException(currclass.getName(),
  1126.                         "IllegalAccessException");
  1127.         } catch (InstantiationException e) {
  1128.         throw new InvalidClassException(currclass.getName(),
  1129.                         "InstantiationException");
  1130.         }
  1131.         handle = assignWireOffset(currentObject);
  1132.         
  1133.         /* 
  1134.          * For all the pushed descriptors and classes.
  1135.          * If there is a descriptor but no class, skip the
  1136.          * data for that class.
  1137.          * If there is a class but no descriptor, just advance,
  1138.          * The classes fields have already been initialized to default
  1139.          * values.
  1140.          * Otherwise, there is both a descriptor and class,
  1141.          *     if the class has its own writeObject and readObject methods
  1142.          *        set blockData = true; and call the readObject method
  1143.          *    else
  1144.          *        invoke the defaultReadObject method
  1145.          *    if the stream was written by class specific methods
  1146.          *        skip any remaining data a objects until TC_ENDBLOCKDATA
  1147.          * Avoid setting BlockData=true unless necessary becase it flushes
  1148.          * the buffer.
  1149.          */
  1150.         try {
  1151.         for (spClass = spClass; spClass > spBase; spClass--) {
  1152.             /*
  1153.              * Set current descriptor and corresponding class
  1154.              */
  1155.             currentClassDesc = classdesc[spClass];
  1156.             currentClass = classes[spClass];
  1157.  
  1158.             if (classes[spClass] != null) {
  1159.             /* Read the data from the stream described by the
  1160.              * descriptor and store into the matching class.
  1161.              */
  1162.             setBlockData(true);    /* any reads are from datablocks */
  1163.             ObjectStreamClass localDesc = currentClassDesc.localClassDescriptor();
  1164.             if (!invokeObjectReader(currentObject)) {
  1165.                 defaultReadObject();
  1166.             }
  1167.             } else {
  1168.             /* No local class for this descriptor,
  1169.              * Skip over the data for this class.
  1170.              * like defaultReadObject with a null currentObject.
  1171.              * The code will read the values but discard them.
  1172.              */
  1173.             ObjectStreamField[] fields = 
  1174.                 currentClassDesc.getFieldsNoCopy();
  1175.             if (fields.length > 0) {
  1176.                 boolean prevmode = setBlockData(false);
  1177.                 inputClassFields(null, currentClass, fields);
  1178.                 setBlockData(prevmode);
  1179.             }
  1180.             }
  1181.  
  1182.             /*
  1183.              * If the source class (stream) had a write object method
  1184.              * it may have written more data and will have written the
  1185.              * TC_ENDBLOCKDATA.  Skip anything up to that and read it.
  1186.              */
  1187.             if (currentClassDesc.hasWriteObject()) {
  1188.             SkipToEndOfBlockData();
  1189.             }
  1190.             setBlockData(false);
  1191.         }
  1192.         } finally {
  1193.         // Make sure we exit at the same stack level as when we started.
  1194.         spClass = spBase;
  1195.         }
  1196.     }
  1197.     return handle;
  1198.     }
  1199.  
  1200.     /*
  1201.      * Skip any unread block data and objects up to the next
  1202.      * TC_ENDBLOCKDATA.  Anybody can do this because readObject
  1203.      * handles the details of reporting if there is data left.
  1204.      * Try reading objects.  If it throws optional data
  1205.      * skip over it and try again. 
  1206.      */
  1207.     private void SkipToEndOfBlockData()
  1208.     throws IOException, ClassNotFoundException
  1209.     {
  1210.     while (peekCode() != TC_ENDBLOCKDATA) {
  1211.         try {
  1212.  
  1213.         /* do not require a local Class equivalent of object being read.*/
  1214.         Object ignore = readObject(false);
  1215.         } catch (OptionalDataException data) {
  1216.         if (data.length > 0)
  1217.             skip(data.length);
  1218.         }
  1219.     }
  1220.     readCode();            /* Consume TC_ENDBLOCKDATA */
  1221.     }
  1222.     
  1223.     /*
  1224.      * Reset the stream to be just like it was after the constructor.
  1225.      */
  1226.     private void resetStream() throws IOException {
  1227.     if (wireHandle2Object == null)
  1228.         wireHandle2Object = new ArrayList();
  1229.     else
  1230.         wireHandle2Object.clear();
  1231.     nextWireOffset = 0;
  1232.  
  1233.     if (classes == null)
  1234.         classes = new Class[20];
  1235.     else {
  1236.         for (int i = 0; i < classes.length; i++)
  1237.         classes[i] = null;
  1238.     }
  1239.     if (classdesc == null)
  1240.         classdesc = new ObjectStreamClass[20];
  1241.     else {
  1242.         for (int i = 0; i < classdesc.length; i++)
  1243.         classdesc[i] = null;
  1244.     }
  1245.     spClass = 0;
  1246.  
  1247.     setBlockData(true);        // Re-enable buffering
  1248.     if (callbacks != null)
  1249.         callbacks.clear();    // discard any pending callbacks
  1250.     }
  1251.  
  1252.     /* Allocate a handle for an object.
  1253.      * The list is indexed by the wireHandleOffset
  1254.      * and contains the object.
  1255.      */
  1256.     private int assignWireOffset(Object obj)
  1257.     throws IOException
  1258.     {
  1259.     wireHandle2Object.add(obj);
  1260.     if (++nextWireOffset != wireHandle2Object.size())
  1261.       throw new StreamCorruptedException(
  1262.           "Elements not assigned in order");
  1263.     return nextWireOffset-1;
  1264.     }
  1265.  
  1266.     /*
  1267.      * Peek at the next control code in the stream.
  1268.      * If the code has not been peeked at yet, read it from the stream.
  1269.      */
  1270.     private byte peekCode() throws IOException, StreamCorruptedException{
  1271.     while (currCode == 0) {
  1272.  
  1273.         int newcode = in.read();    // Read byte from the underlying stream
  1274.         if (newcode < 0) 
  1275.         throw new EOFException("Expecting code");
  1276.         
  1277.         currCode = (byte)newcode;
  1278.         if (currCode < TC_BASE || currCode > TC_MAX)
  1279.         throw new StreamCorruptedException("Type code out of range, is " + currCode);
  1280.  
  1281.         /* 
  1282.          * Handle reset as a hidden code and reset the stream.
  1283.          */
  1284.         if (currCode == TC_RESET) {
  1285.         if (recursionDepth != 0 ||
  1286.             currentObject != null ||
  1287.             currentClassDesc != null)
  1288.             throw new StreamCorruptedException("Illegal stream state for reset");
  1289.         
  1290.         /* Reset the stream, and repeat the peek at the next code
  1291.          */
  1292.         resetStream();
  1293.         currCode = 0;
  1294.         }
  1295.     }
  1296.     return currCode;
  1297.     }
  1298.     
  1299.     /*
  1300.      * Return the next control code in the stream.
  1301.      * peekCode gets the next code.  readCode just consumes it.
  1302.      */
  1303.     private byte readCode()
  1304.     throws IOException, StreamCorruptedException
  1305.     {
  1306.     byte tc = peekCode();
  1307.     currCode = 0;
  1308.     return tc;
  1309.     }
  1310.     
  1311.     /*
  1312.      * Put back the specified code to be peeked at next time.
  1313.      */
  1314.     private void pushbackCode(byte code) {
  1315.     currCode = code;
  1316.     }
  1317.     /* -----------------------------------------------------*/
  1318.     /*
  1319.      * Implement the InputStream methods.  The stream has
  1320.      * two modes used internally to ObjectInputStream.  When
  1321.      * in BlockData mode, all reads are only from datablocks
  1322.      * as original written. End of data (-1) is returned
  1323.      * if something other than a datablock is next in the stream.
  1324.      * When not in BlockData mode (false), reads pass directly
  1325.      * through to the underlying stream.
  1326.      * The BlockData mode is used to encapsulate data written
  1327.      * by class specific writeObject methods that is intended
  1328.      * only to be read by corresponding readObject method of the 
  1329.      * same class.  The blocking of data allows it to be skipped
  1330.      * if necessary.
  1331.      *
  1332.      * The setBlockData method is used to switch buffering
  1333.      * on and off.  When switching between on and off 
  1334.      * there must be no data pending to be read. This is 
  1335.      * an internal consistency check that will throw an exception. 
  1336.      *
  1337.      */
  1338.     private InputStream in;
  1339.  
  1340.     /*
  1341.      * Count of bytes available from blockData, if zero, call refill
  1342.      * to look for more.  If -1 always return eof (-1)
  1343.      */
  1344.     private int count;
  1345.         
  1346.     private boolean blockDataMode;
  1347.  
  1348.     private byte[] buffer;    // buffer for reading array data
  1349.  
  1350.     /*
  1351.      * Set the blockdata buffering mode.
  1352.      * If it is being set to false after being true there must
  1353.      * be no pending data. If count > 0 a corrupted exception is thrown.
  1354.      */
  1355.     private boolean setBlockData(boolean mode) throws IOException {
  1356.     if (blockDataMode == mode)
  1357.         return mode;
  1358.     if (blockDataMode && count > 0)
  1359.         throw new StreamCorruptedException("Unread data");
  1360.  
  1361.     /* Set count to allow reading or not */
  1362.     count =  mode ? 0 : -1;
  1363.  
  1364.     blockDataMode = mode;
  1365.     return !mode;
  1366.     }
  1367.     
  1368.     /**
  1369.      * Reads a byte of data. This method will block if no input is 
  1370.      * available.
  1371.      * @return     the byte read, or -1 if the end of the
  1372.      *        stream is reached.
  1373.      * @exception IOException If an I/O error has occurred.
  1374.      */
  1375.     public int read() throws IOException {
  1376.     int data;
  1377.     if (blockDataMode) {
  1378.         while (count == 0)
  1379.         refill();
  1380.         if (count < 0)
  1381.         return -1;            /* EOF */
  1382.         data = in.read();
  1383.         if (data >= 0)
  1384.         count--;
  1385.     } else {
  1386.         data = in.read();        /* read directly from input stream */
  1387.     }
  1388.     return data;
  1389.     }
  1390.  
  1391.     /*
  1392.      * Expect the next thing in the stream is a datablock, If its a
  1393.      * datablock, extract the count of bytes to allow.  If data is not
  1394.      * available set the count to zero.  On error or EOF, set count to -1.
  1395.      */
  1396.     private void refill() throws IOException {
  1397.     count = -1;        /*  No more data to read, EOF */
  1398.     byte code;
  1399.     try {
  1400.         code = peekCode();
  1401.     } catch (EOFException e) {
  1402.         return;
  1403.     }
  1404.     if (code == TC_BLOCKDATA) {
  1405.         code = readCode();            /* Consume the code */
  1406.         int c = in.read();
  1407.         if (c < 0)
  1408.         throw new StreamCorruptedException("EOF expecting count");
  1409.         
  1410.         count = c & 0xff;
  1411.     } else if (code == TC_BLOCKDATALONG) {
  1412.         code = readCode();
  1413.         int b3 = in.read();
  1414.         int b2 = in.read();
  1415.         int b1 = in.read();
  1416.         int b0 = in.read();
  1417.         if ((b3 | b2 | b1 | b0) < 0)
  1418.         throw new StreamCorruptedException("EOF expecting count");
  1419.         int c = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
  1420.         /*
  1421.          * The 32 bit integer size in the long block data format is
  1422.          * signed (unlike like the normal block data format), and
  1423.          * negative values are invalid.
  1424.          */
  1425.         if (c < 0)
  1426.         throw new StreamCorruptedException("Negative block data size");
  1427.  
  1428.         count = c;
  1429.     }
  1430.     }
  1431.     
  1432.     /**
  1433.      * Reads into an array of bytes.  This method will
  1434.      * block until some input is available. Consider
  1435.      * using java.io.DataInputStream.readFully to read exactly
  1436.      * 'length' bytes.
  1437.      * @param b    the buffer into which the data is read
  1438.      * @param off the start offset of the data
  1439.      * @param len the maximum number of bytes read
  1440.      * @return  the actual number of bytes read, -1 is
  1441.      *         returned when the end of the stream is reached.
  1442.      * @exception IOException If an I/O error has occurred.
  1443.      * @see java.io.DataInputStream#readFully(byte[],int,int)
  1444.      */
  1445.     public int read(byte[] b, int off, int len) throws IOException {
  1446.     int v;
  1447.     int i;
  1448.  
  1449.     if (b == null) {
  1450.         throw new NullPointerException();
  1451.     } else if ((off < 0) || (off > b.length) || (len < 0) ||
  1452.            ((off + len) > b.length) || ((off + len) < 0)) {
  1453.         throw new IndexOutOfBoundsException();
  1454.     } else if (len == 0) {
  1455.         return 0;
  1456.     }
  1457.  
  1458.     if (blockDataMode) {
  1459.         while (count == 0)
  1460.         refill();
  1461.         if (count < 0)
  1462.         return -1;
  1463.         int l = Math.min(len, count);
  1464.         i = in.read(b, off, l);
  1465.         if (i > 0)
  1466.         count -= i;
  1467.         return i;            /* return number of bytes read */
  1468.     } else {
  1469.         /* read directly from input stream */
  1470.         return in.read(b, off, len);
  1471.     }
  1472.     }
  1473.  
  1474.     /**
  1475.      * Returns the number of bytes that can be read without blocking.
  1476.      * @return the number of available bytes.
  1477.      */
  1478.     public int available() throws IOException {
  1479.     /*
  1480.      * If in blockdataMode returns the number of bytes in the
  1481.      * current block. If that is zero, it will try to read
  1482.      * another blockdata from the stream if any data is available from the
  1483.      * underlying stream..
  1484.      * If not in blockdata mode it returns zero.
  1485.      */
  1486.     if (blockDataMode) {
  1487.         if (count == 0 && in.available() > 0)
  1488.         refill();
  1489.         if (count >= 0) {
  1490.         return count;
  1491.         } else
  1492.         return 0;    /* EOF is no bytes available */
  1493.     } else {
  1494.         return 0;        /* Not blockdata, no bytes available */
  1495.     }
  1496.     }
  1497.  
  1498.     /**
  1499.      * Closes the input stream. Must be called
  1500.      * to release any resources associated with
  1501.      * the stream.
  1502.      * @exception IOException If an I/O error has occurred.
  1503.      */
  1504.     public void close() throws IOException {
  1505.     in.close();
  1506.     }
  1507.  
  1508.     /* -----------------------------------------------------*/
  1509.     /*
  1510.      * Provide the methods to implement DataInput.
  1511.      * They delegate to an Instance of DataInputStream that
  1512.      * reads its input from the ObjectInputStream.
  1513.      * This allows this stream to manage the blocked data the data
  1514.      * as necessary.
  1515.      */
  1516.     private DataInputStream dis;
  1517.     
  1518.     /**
  1519.      * Reads in a boolean.
  1520.      * @return the boolean read.
  1521.      * @exception EOFException If end of file is reached.
  1522.      * @exception IOException If other I/O error has occurred.
  1523.      */
  1524.     public boolean readBoolean() throws IOException {
  1525.     return dis.readBoolean();
  1526.     }
  1527.  
  1528.     /**
  1529.      * Reads an 8 bit byte.
  1530.      * @return the 8 bit byte read.
  1531.      * @exception EOFException If end of file is reached.
  1532.      * @exception IOException If other I/O error has occurred.
  1533.      */
  1534.     public byte readByte() throws IOException  {
  1535.     return dis.readByte();
  1536.     }
  1537.  
  1538.     /**
  1539.      * Reads an unsigned 8 bit byte.
  1540.      * @return the 8 bit byte read.
  1541.      * @exception EOFException If end of file is reached.
  1542.      * @exception IOException If other I/O error has occurred.
  1543.      */
  1544.     public int readUnsignedByte()  throws IOException {
  1545.     return dis.readUnsignedByte();
  1546.     }
  1547.  
  1548.     /**
  1549.      * Reads a 16 bit short.
  1550.      * @return the 16 bit short read.
  1551.      * @exception EOFException If end of file is reached.
  1552.      * @exception IOException If other I/O error has occurred.
  1553.      */
  1554.     public short readShort()  throws IOException {
  1555.     return dis.readShort();
  1556.     }
  1557.  
  1558.     /**
  1559.      * Reads an unsigned 16 bit short.
  1560.      * @return the 16 bit short read.
  1561.      * @exception EOFException If end of file is reached.
  1562.      * @exception IOException If other I/O error has occurred.
  1563.      */
  1564.     public int readUnsignedShort() throws IOException {
  1565.     return dis.readUnsignedShort();
  1566.     }
  1567.  
  1568.     /**
  1569.      * Reads a 16 bit char.
  1570.      * @return the 16 bit char read. 
  1571.      * @exception EOFException If end of file is reached.
  1572.      * @exception IOException If other I/O error has occurred.
  1573.      */
  1574.     public char readChar()  throws IOException {
  1575.     return dis.readChar();
  1576.     }
  1577.  
  1578.     /**
  1579.      * Reads a 32 bit int.
  1580.      * @return the 32 bit integer read.
  1581.      * @exception EOFException If end of file is reached.
  1582.      * @exception IOException If other I/O error has occurred.
  1583.      */
  1584.     public int readInt()  throws IOException {
  1585.     return dis.readInt();
  1586.     }
  1587.  
  1588.     /**
  1589.      * Reads a 64 bit long.
  1590.      * @return the read 64 bit long.
  1591.      * @exception EOFException If end of file is reached.
  1592.      * @exception IOException If other I/O error has occurred.
  1593.      */
  1594.     public long readLong()  throws IOException {
  1595.     return dis.readLong();
  1596.     }
  1597.  
  1598.     /**
  1599.      * Reads a 32 bit float.
  1600.      * @return the 32 bit float read.
  1601.      * @exception EOFException If end of file is reached.
  1602.      * @exception IOException If other I/O error has occurred.
  1603.      */
  1604.     public float readFloat() throws IOException {
  1605.     return dis.readFloat();
  1606.     }
  1607.  
  1608.     /**
  1609.      * Reads a 64 bit double.
  1610.      * @return the 64 bit double read.
  1611.      * @exception EOFException If end of file is reached.
  1612.      * @exception IOException If other I/O error has occurred.
  1613.      */
  1614.     public double readDouble() throws IOException {
  1615.     return dis.readDouble();
  1616.     }
  1617.  
  1618.     /**
  1619.      * Reads bytes, blocking until all bytes are read.
  1620.      * @param b    the buffer into which the data is read
  1621.      * @exception EOFException If end of file is reached.
  1622.      * @exception IOException If other I/O error has occurred.
  1623.      */
  1624.     public void readFully(byte[] data) throws IOException {
  1625.     dis.readFully(data);
  1626.     }
  1627.  
  1628.     /**
  1629.      * Reads bytes, blocking until all bytes are read.
  1630.      * @param b    the buffer into which the data is read
  1631.      * @param off the start offset of the data
  1632.      * @param len the maximum number of bytes to read
  1633.      * @exception EOFException If end of file is reached.
  1634.      * @exception IOException If other I/O error has occurred.
  1635.      */
  1636.     public void readFully(byte[] data, int offset, int size) throws IOException {
  1637.     if (size < 0)
  1638.         throw new IndexOutOfBoundsException();
  1639.     
  1640.     dis.readFully(data, offset, size);
  1641.     }
  1642.  
  1643.     /**
  1644.      * Skips bytes, block until all bytes are skipped.
  1645.      * @param n the number of bytes to be skipped
  1646.      * @return    the actual number of bytes skipped.
  1647.      * @exception EOFException If end of file is reached.
  1648.      * @exception IOException If other I/O error has occurred.
  1649.      */
  1650.     public int skipBytes(int len) throws IOException {
  1651.     return dis.skipBytes(len);
  1652.     }
  1653.  
  1654.     /**
  1655.      * Reads in a line that has been terminated by a \n, \r, 
  1656.      * \r\n or EOF.
  1657.      * @return a String copy of the line.
  1658.      * @deprecated This method does not properly convert bytes to characters.
  1659.      * see DataInputStream for the details and alternatives.
  1660.      */
  1661.     public String readLine() throws IOException {
  1662.     return dis.readLine();
  1663.     }
  1664.  
  1665.     /**
  1666.      * Reads a UTF format String.
  1667.      * @return the String.
  1668.      */
  1669.      public String readUTF() throws IOException {
  1670.     return dis.readUTF();
  1671.     }
  1672.     
  1673.     /*
  1674.      * Invoke the readObject method if present
  1675.      */
  1676.     private boolean invokeObjectReader(Object obj)
  1677.     throws InvalidClassException, StreamCorruptedException,
  1678.         ClassNotFoundException, IOException
  1679.     {
  1680.     if (currentClassDesc.readObjectMethod == null)
  1681.         return false;
  1682.  
  1683.     try {
  1684.         currentClassDesc.readObjectMethod.invoke(obj, readObjectArglist);
  1685.         return true;
  1686.     } catch (InvocationTargetException e) {
  1687.         Throwable t = e.getTargetException();
  1688.         if (t instanceof ClassNotFoundException)
  1689.         throw (ClassNotFoundException)t;
  1690.         else if (t instanceof IOException)
  1691.         throw (IOException)t;
  1692.         else if (t instanceof RuntimeException)
  1693.         throw (RuntimeException) t;
  1694.         else if (t instanceof Error)
  1695.         throw (Error) t;
  1696.         else
  1697.         throw new Error("interal error");
  1698.     } catch (IllegalAccessException e) {
  1699.         return false;
  1700.     }
  1701.     }
  1702.  
  1703.     /*
  1704.      * Read the fields of the specified class from the input stream and set
  1705.      * the values of the fields in the specified object. If the specified
  1706.      * object is null, just consume the fields without setting any values. If
  1707.      * any ObjectStreamField does not have a reflected Field, don't try to set
  1708.      * that field in the object.
  1709.      */
  1710.     private void inputClassFields(Object o, Class cl,
  1711.                   ObjectStreamField[] fields) 
  1712.     throws InvalidClassException, StreamCorruptedException,
  1713.         ClassNotFoundException, IOException
  1714.     {
  1715.     int primFields = fields.length - currentClassDesc.objFields;
  1716.  
  1717.     /*
  1718.      * Read and dispatch primitive data fields from the input
  1719.      * stream.
  1720.      */
  1721.       if (currentClassDesc.primBytes > 0) {
  1722.         if (data == null) {
  1723.         data = new byte[Math.max(currentClassDesc.primBytes,
  1724.                      INITIAL_BUFFER_SIZE)];
  1725.         } else if (data.length < currentClassDesc.primBytes) {
  1726.         data = new byte[currentClassDesc.primBytes];
  1727.         }
  1728.         readFully(data, 0, currentClassDesc.primBytes);
  1729.     }
  1730.  
  1731.     if (o != null) {
  1732.         for (int i = 0; i < primFields; ++i) {
  1733.         if (fields[i].getField() == null)
  1734.             continue;
  1735.  
  1736.         try {
  1737.             int lower;
  1738.             int upper;
  1739.             int loffset = fields[i].getOffset();
  1740.             
  1741.             switch (fields[i].getTypeCode()) {
  1742.             case 'B':
  1743.             byte byteValue = data[loffset];
  1744.             fields[i].getField().setByte(o, byteValue);
  1745.             break;
  1746.             case 'Z':
  1747.             boolean booleanValue =
  1748.                 (boolean)(data[loffset] != 0);
  1749.             fields[i].getField().setBoolean(o, booleanValue);
  1750.             break;
  1751.             case 'C':
  1752.             char charValue =
  1753.                 (char)(((data[loffset] & 0xff) << 8) +
  1754.                    ((data[loffset+1] & 0xff)));
  1755.             fields[i].getField().setChar(o, charValue);
  1756.             break;
  1757.             case 'S': 
  1758.             short shortValue =
  1759.                 (short)(((data[loffset] & 0xff) << 8) +
  1760.                     ((data[loffset+1] & 0xff)));
  1761.             fields[i].getField().setShort(o, shortValue);
  1762.             break;
  1763.             case 'I':
  1764.             int intValue =
  1765.                 (((data[loffset]   & 0xff) << 24) +
  1766.                  ((data[loffset+1] & 0xff) << 16) +
  1767.                  ((data[loffset+2] & 0xff) << 8) +
  1768.                  ((data[loffset+3] & 0xff)));
  1769.             fields[i].getField().setInt(o, intValue);
  1770.             break;
  1771.             case 'J':
  1772.             upper = (((data[loffset]   & 0xff) << 24) +
  1773.                  ((data[loffset+1] & 0xff) << 16) +
  1774.                  ((data[loffset+2] & 0xff) << 8) +
  1775.                  ((data[loffset+3] & 0xff)));
  1776.             lower = (((data[loffset+4] & 0xff) << 24) +
  1777.                  ((data[loffset+5] & 0xff) << 16) +
  1778.                  ((data[loffset+6] & 0xff) << 8) +
  1779.                  ((data[loffset+7] & 0xff)));
  1780.             long longValue =
  1781.                 ((long)upper << 32) + ((long) lower & 0xFFFFFFFFL);
  1782.             fields[i].getField().setLong(o, longValue);
  1783.             break;
  1784.             case 'F' :
  1785.             int v = (((data[loffset]   & 0xff) << 24) +
  1786.                  ((data[loffset+1] & 0xff) << 16) +
  1787.                  ((data[loffset+2] & 0xff) << 8) +
  1788.                  ((data[loffset+3] & 0xff)));
  1789.             float floatValue = Float.intBitsToFloat(v);
  1790.             fields[i].getField().setFloat(o, floatValue);
  1791.             break;
  1792.             case 'D' :
  1793.             upper = (((data[loffset] & 0xff) << 24) +
  1794.                  ((data[loffset+1] & 0xff) << 16) +
  1795.                  ((data[loffset+2] & 0xff) << 8) +
  1796.                  ((data[loffset+3] & 0xff)));
  1797.             lower = (((data[loffset+4] & 0xff) << 24) +
  1798.                  ((data[loffset+5] & 0xff) << 16) +
  1799.                  ((data[loffset+6] & 0xff) << 8) +
  1800.                  ((data[loffset+7] & 0xff)));
  1801.             long vv =
  1802.                 ((long) upper << 32) + ((long)lower & 0xFFFFFFFFL);
  1803.             double doubleValue = Double.longBitsToDouble(vv);
  1804.             fields[i].getField().setDouble(o, doubleValue);
  1805.             break;
  1806.             default:
  1807.             // "Impossible"
  1808.             throw new InvalidClassException(cl.getName());
  1809.             }
  1810.         } catch (IllegalAccessException e) {
  1811.             throw new InvalidClassException(cl.getName(),
  1812.                             "IllegalAccessException");
  1813.         } catch (IllegalArgumentException e) {
  1814.             /* This case should never happen. If the field types
  1815.                are not the same, InvalidClassException is raised when
  1816.                matching the local class to the serialized ObjectStreamClass. */
  1817.             throw new ClassCastException("Assigning instance of class " +
  1818.                          fields[i].getType().getName() +
  1819.                          " to field " +
  1820.                          currentClassDesc.getName() + '#' +
  1821.                          fields[i].getField().getName());
  1822.         }
  1823.         }
  1824.     }
  1825.  
  1826.     /* Read and set object fields from the input stream. */
  1827.     if (currentClassDesc.objFields > 0) {
  1828.         for (int i = primFields; i < fields.length; i++) {
  1829.         boolean requireLocalClass = (fields[i].getField() != null);
  1830.         Object objectValue = readObject(requireLocalClass);
  1831.         if ((o == null) || (fields[i].getField() == null)) {
  1832.             continue;
  1833.         }
  1834.         try {
  1835.             fields[i].getField().set(o, objectValue);
  1836.         } catch (IllegalAccessException e) {
  1837.             throw new InvalidClassException(cl.getName(),
  1838.                             "IllegalAccessException");
  1839.         } catch (IllegalArgumentException e) {
  1840.             throw new ClassCastException("Assigning instance of class " +
  1841.                          objectValue.getClass().getName() +
  1842.                          " to field " +
  1843.                          currentClassDesc.getName() +
  1844.                          '#' +
  1845.                          fields[i].getField().getName());
  1846.         }
  1847.         }
  1848.     }
  1849.     }
  1850.  
  1851.     /*************************************************************/
  1852.  
  1853.     /**
  1854.      * Provide access to the persistent fields read from the input stream.
  1855.      */
  1856.     abstract public static class GetField {
  1857.  
  1858.      /**
  1859.       * Get the ObjectStreamClass that describes the fields in the stream.
  1860.       */
  1861.      abstract public ObjectStreamClass getObjectStreamClass();
  1862.  
  1863.      /**
  1864.       * Return true if the named field is defaulted and has no value
  1865.       * in this stream.
  1866.       */
  1867.      abstract public boolean defaulted(String name)
  1868.          throws IOException, IllegalArgumentException;
  1869.  
  1870.     /**
  1871.      * Get the value of the named boolean field from the persistent field.
  1872.      */
  1873.     abstract public boolean get(String name, boolean defvalue) 
  1874.         throws IOException, IllegalArgumentException;
  1875.  
  1876.     /**
  1877.      * Get the value of the named char field from the persistent fields.
  1878.      */
  1879.     abstract public char get(String name, char defvalue) 
  1880.         throws IOException, IllegalArgumentException;
  1881.  
  1882.     /**
  1883.      * Get the value of the named byte field from the persistent fields.
  1884.      */
  1885.     abstract public byte get(String name, byte defvalue) 
  1886.         throws IOException, IllegalArgumentException;
  1887.  
  1888.     /**
  1889.      * Get the value of the named short field from the persistent fields.
  1890.      */
  1891.     abstract public short get(String name, short defvalue) 
  1892.         throws IOException, IllegalArgumentException;
  1893.  
  1894.     /**
  1895.      * Get the value of the named int field from the persistent fields.
  1896.      */
  1897.     abstract public int get(String name, int defvalue) 
  1898.         throws IOException, IllegalArgumentException;
  1899.  
  1900.     /**
  1901.      * Get the value of the named long field from the persistent fields.
  1902.      */
  1903.     abstract public long get(String name, long defvalue)
  1904.         throws IOException, IllegalArgumentException;
  1905.  
  1906.     /**
  1907.      * Get the value of the named float field from the persistent fields.
  1908.      */
  1909.     abstract public float get(String name, float defvalue) 
  1910.         throws IOException, IllegalArgumentException;
  1911.  
  1912.     /**
  1913.      * Get the value of the named double field from the persistent field.
  1914.      */
  1915.     abstract public double get(String name, double defvalue) 
  1916.         throws IOException, IllegalArgumentException;
  1917.  
  1918.     /**
  1919.      * Get the value of the named Object field from the persistent field.
  1920.      */
  1921.     abstract public Object get(String name, Object defvalue) 
  1922.         throws IOException, IllegalArgumentException;
  1923.     }
  1924.  
  1925.     /* Internal Implementation of GetField. */
  1926.     static final class GetFieldImpl extends GetField {
  1927.  
  1928.         /**
  1929.          * Get the ObjectStreamClass that describes the fields in the stream.
  1930.          */
  1931.         public ObjectStreamClass getObjectStreamClass() {
  1932.         return desc;
  1933.         }
  1934.  
  1935.         /**
  1936.          * Return true if the named field is defaulted and has no value
  1937.          * in this stream.
  1938.          */
  1939.         public boolean defaulted(String name)
  1940.         throws IOException, IllegalArgumentException
  1941.         {
  1942.             ObjectStreamField field = checkField(name, null);
  1943.             return (field == null);       
  1944.         }
  1945.  
  1946.         /**
  1947.          * Get the value of the named boolean field from the persistent field.
  1948.          */
  1949.         public boolean get(String name, boolean defvalue) 
  1950.         throws IOException, IllegalArgumentException
  1951.         {
  1952.             ObjectStreamField field = checkField(name, Boolean.TYPE);
  1953.             if (field == null)
  1954.             return defvalue;
  1955.  
  1956.             return (boolean)(data[field.getOffset()] != 0);
  1957.         }
  1958.  
  1959.         /**
  1960.          * Get the value of the named char field from the persistent fields.
  1961.          */
  1962.         public char get(String name, char defvalue) 
  1963.         throws IOException, IllegalArgumentException
  1964.         {
  1965.             ObjectStreamField field = checkField(name, Character.TYPE);
  1966.             if (field == null)
  1967.             return defvalue;
  1968.  
  1969.             int loffset = field.getOffset();
  1970.             return (char)(((data[loffset] & 0xff) << 8) +
  1971.                   ((data[loffset+1] & 0xff)));
  1972.         }
  1973.  
  1974.         /**
  1975.          * Get the value of the named byte field from the persistent fields.
  1976.          */
  1977.         public byte get(String name, byte defvalue) 
  1978.         throws IOException, IllegalArgumentException
  1979.         {
  1980.             ObjectStreamField field = checkField(name, Byte.TYPE);
  1981.             if (field == null)
  1982.             return defvalue;
  1983.  
  1984.             return data[field.getOffset()];
  1985.         }
  1986.  
  1987.         /**
  1988.          * Get the value of the named short field from the persistent fields.
  1989.          */
  1990.         public short get(String name, short defvalue) 
  1991.         throws IOException, IllegalArgumentException
  1992.         {
  1993.             ObjectStreamField field = checkField(name, Short.TYPE);
  1994.             if (field == null)
  1995.             return defvalue;
  1996.  
  1997.             int loffset = field.getOffset();
  1998.             return (short)(((data[loffset] & 0xff) << 8) +
  1999.                    ((data[loffset+1] & 0xff)));
  2000.         }
  2001.  
  2002.         /**
  2003.          * Get the value of the named int field from the persistent fields.
  2004.          */
  2005.         public int get(String name, int defvalue) 
  2006.         throws IOException, IllegalArgumentException
  2007.         {
  2008.             ObjectStreamField field = checkField(name, Integer.TYPE);
  2009.             if (field == null)
  2010.             return defvalue;
  2011.  
  2012.             int loffset = field.getOffset();         
  2013.             return (((data[loffset] & 0xff) << 24) +
  2014.                 ((data[loffset+1] & 0xff) << 16) +
  2015.                 ((data[loffset+2] & 0xff) << 8) +
  2016.                 ((data[loffset+3] & 0xff)));
  2017.         }
  2018.  
  2019.         /**
  2020.          * Get the value of the named long field from the persistent fields.
  2021.          */
  2022.         public long get(String name, long defvalue) 
  2023.         throws IOException, IllegalArgumentException
  2024.         {
  2025.             ObjectStreamField field = checkField(name, Long.TYPE);
  2026.             if (field == null)
  2027.             return defvalue;
  2028.  
  2029.             int loffset = field.getOffset();         
  2030.             int upper = (((data[loffset] & 0xff) << 24) +
  2031.                  ((data[loffset+1] & 0xff) << 16) +
  2032.                  ((data[loffset+2] & 0xff) << 8) +
  2033.                  ((data[loffset+3] & 0xff)));
  2034.             int lower = (((data[loffset+4] & 0xff) << 24) +
  2035.                  ((data[loffset+5] & 0xff) << 16) +
  2036.                  ((data[loffset+6] & 0xff) << 8) +
  2037.                  ((data[loffset+7] & 0xff)));
  2038.             long v = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  2039.             return v;
  2040.         }
  2041.  
  2042.         /**
  2043.          * Get the value of the named float field from the persistent fields.
  2044.          */
  2045.         public float get(String name, float defvalue) 
  2046.         throws IOException, IllegalArgumentException
  2047.         {
  2048.             ObjectStreamField field = checkField(name, Float.TYPE);
  2049.             if (field == null)
  2050.             return defvalue;
  2051.  
  2052.             int loffset = field.getOffset();         
  2053.             int v = (((data[loffset] & 0xff) << 24) +
  2054.                  ((data[loffset+1] & 0xff) << 16) +
  2055.                  ((data[loffset+2] & 0xff) << 8) +
  2056.                  ((data[loffset+3] & 0xff)));
  2057.             return Float.intBitsToFloat(v);
  2058.         }
  2059.  
  2060.         /**
  2061.          * Get the value of the named double field from the persistent field.
  2062.          */
  2063.         public double get(String name, double defvalue) 
  2064.         throws IOException, IllegalArgumentException
  2065.         {
  2066.             ObjectStreamField field = checkField(name, Double.TYPE);
  2067.             if (field == null)
  2068.             return defvalue;
  2069.  
  2070.             int loffset = field.getOffset();         
  2071.             int upper = (((data[loffset] & 0xff) << 24) +
  2072.                  ((data[loffset+1] & 0xff) << 16) +
  2073.                  ((data[loffset+2] & 0xff) << 8) +
  2074.                  ((data[loffset+3] & 0xff)));
  2075.             int lower = (((data[loffset+4] & 0xff) << 24) +
  2076.                  ((data[loffset+5] & 0xff) << 16) +
  2077.                  ((data[loffset+6] & 0xff) << 8) +
  2078.                  ((data[loffset+7] & 0xff)));
  2079.             long v = ((long)upper << 32) + ((long)lower & 0xFFFFFFFFL);
  2080.             return Double.longBitsToDouble(v);
  2081.         }
  2082.  
  2083.         /**
  2084.          * Get the value of the named Object field from the persistent field.
  2085.          */
  2086.         public Object get(String name, Object defvalue) 
  2087.         throws IOException, IllegalArgumentException
  2088.         {
  2089.             ObjectStreamField field = checkField(name, Object.class);
  2090.             if (field == null)
  2091.             return defvalue;
  2092.  
  2093.             return objects[field.getOffset()];
  2094.  
  2095.         }
  2096.  
  2097.         /*
  2098.          * Retrieve the named field.
  2099.          * If the field is known in the current descriptor return it.
  2100.          * If not, find the descriptor for the class that is being
  2101.          * read into and check the name.  If the name is not
  2102.          * valid in the class throw a IllegalArgumentException.
  2103.          * otherwise return null.
  2104.          */
  2105.         private ObjectStreamField checkField(String name, Class type)
  2106.         throws IllegalArgumentException
  2107.         {
  2108.             ObjectStreamField field = (type == null) ? 
  2109.             desc.getField(name) : desc.getField(name, type);
  2110.             if (field != null) {
  2111.             /*
  2112.              * Check the type of the field in the stream.
  2113.              * If correct return the field.
  2114.              */
  2115.             if (type != null && type != field.getType())
  2116.                 throw new IllegalArgumentException("field type incorrect");
  2117.             return field;
  2118.             } else {
  2119.             /* Check the name in the local classes descriptor.
  2120.              * If found it's a valid persistent field an
  2121.              * should be defaulted.
  2122.              * If not the caller shouldn't be using that name.
  2123.              */
  2124.             ObjectStreamClass localdesc =
  2125.                 desc.localClassDescriptor();
  2126.             if (localdesc == null)
  2127.                 throw new IllegalArgumentException("No local class descriptor");
  2128.  
  2129.             ObjectStreamField localfield = (type == null)
  2130.                ? localdesc.getField(name) : 
  2131.                 localdesc.getField(name, type);
  2132.             if (localfield == null)
  2133.                 throw new IllegalArgumentException("no such field");
  2134.             if (type != null && type != localfield.getType() &&
  2135.                 (type.isPrimitive() || localfield.getType().isPrimitive()))
  2136.                 throw new IllegalArgumentException("field type incorrect");
  2137.             return null;
  2138.             }
  2139.         }
  2140.  
  2141.         /**
  2142.          * Read the data and fields from the specified stream.
  2143.          */
  2144.         void read(ObjectInputStream in)
  2145.         throws IOException, ClassNotFoundException
  2146.         {
  2147.             if (data != null)
  2148.             in.readFully(data, 0, data.length);
  2149.  
  2150.             if (objects != null) {
  2151.             for (int i = 0; i < objects.length; i++) {
  2152.                 /* don't require local class when reading object from stream.*/
  2153.                 objects[i] = in.readObject(false);
  2154.             }
  2155.             }
  2156.         }
  2157.  
  2158.         /**
  2159.          * Create a GetField object for the a Class.
  2160.          * Allocate the arrays for primitives and objects.
  2161.          */
  2162.         GetFieldImpl(ObjectStreamClass descriptor){
  2163.         desc = descriptor;
  2164.         if (desc.primBytes > 0)
  2165.             data = new byte[desc.primBytes];
  2166.         if (desc.objFields > 0)
  2167.             objects = new Object[desc.objFields];
  2168.         }
  2169.  
  2170.         /*
  2171.          * The byte array that contains the bytes for the primitive fields.
  2172.          * The Object array that contains the objects for the object fields.
  2173.          */
  2174.         private byte[] data;
  2175.         private Object[] objects;
  2176.         private ObjectStreamClass desc;
  2177.     }
  2178.  
  2179.     /* Remember the first exception that stopped this stream. */
  2180.     private IOException abortIOException = null;
  2181.     private ClassNotFoundException abortClassNotFoundException = null;
  2182.  
  2183.     /* Allocate a new object for the specified class
  2184.      * Native since newInstance may not be able to find a zero arg constructor.
  2185.      */
  2186.     private static native Object allocateNewObject(Class aclass, Class initclass)
  2187.     throws InstantiationException, IllegalAccessException;
  2188.     
  2189.     /* Allocate a new array for the specified class
  2190.      * Native since the type of the array needs to be set to the class
  2191.      */
  2192.     private static native Object allocateNewArray(Class aclass, int length);
  2193.     
  2194.     /* The object is the current object and class is the the current
  2195.      * subclass of the object being read. Nesting information is kept
  2196.      * on the stack.
  2197.      */
  2198.     private Object currentObject;
  2199.     private ObjectStreamClass currentClassDesc;
  2200.     private Class currentClass;
  2201.     private Object currentGetFields;
  2202.  
  2203.     /*
  2204.      * Primitive data are read from the input stream and stored in
  2205.      * this array. The array is allocated prior to first use.
  2206.      */
  2207.     private static final int INITIAL_BUFFER_SIZE = 64;
  2208.     private byte[] data;
  2209.  
  2210.     /* Arrays used to keep track of classes and ObjectStreamClasses
  2211.      * as they are being merged; used in inputObject.
  2212.      * spClass is the stack pointer for both.  */
  2213.     ObjectStreamClass[] classdesc;
  2214.     Class[] classes;
  2215.     int spClass;
  2216.  
  2217.     /* During deserialization the objects in the stream are represented by
  2218.      * handles (ints), they need to be mapped to the objects.
  2219.      * The vector is indexed by the offset between baseWireHandle and the
  2220.      * wire handle in the stream.
  2221.      */
  2222.     private ArrayList wireHandle2Object;
  2223.     private int nextWireOffset;
  2224.  
  2225.     /* List of validation callback objects
  2226.      * The list is created as needed, and ValidationCallback objects added
  2227.      * for each call to registerObject. The list is maintained in
  2228.      * order of highest (first) priority to lowest
  2229.      */
  2230.     private ArrayList callbacks;
  2231.  
  2232.     /* Recursion level, starts at zero and is incremented for each entry
  2233.      * to readObject.  Decremented before exit.
  2234.      */ 
  2235.     private int recursionDepth;
  2236.  
  2237.     /* Last code Peek'ed, if any */
  2238.     private byte currCode;
  2239.  
  2240.     /* 
  2241.      * Flag set to true to allow resolveObject to be called.
  2242.      * Set by enableResolveObject.
  2243.      */
  2244.     boolean enableResolve;
  2245.  
  2246.  
  2247.     /* if true, override readObject implementation with readObjectOverride.
  2248.      */
  2249.     private boolean enableSubclassImplementation;
  2250.  
  2251.     private Object[] readObjectArglist = {this};
  2252. };
  2253.  
  2254. // Internal class to hold the Callback object and priority
  2255. class ValidationCallback {
  2256.     ValidationCallback(ObjectInputValidation cb, int prio) {
  2257.     callback = cb;
  2258.     priority = prio;
  2259.     }
  2260.  
  2261.     int priority;            // priority of this callback
  2262.     ObjectInputValidation callback; // object to be called back
  2263. }
  2264.